home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Games Collection 1 / software vault.zip / software vault / CDR10 / MAPEDIT.ZIP / PCX.C < prev    next >
C/C++ Source or Header  |  1992-09-17  |  30KB  |  850 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <conio.h>
  5. #include <dos.h>
  6. #include <malloc.h>
  7. #include <graph.h>
  8.  
  9. #define FALSE           0
  10. #define TRUE            1
  11. #define PCX_HERC        0xff    /* Hercules 720 x 348 monochrome mode   */
  12. #define PCX_COMP_FLAG   0xc0    /* Compressed data flag mask            */
  13. #define PCX_COMP_MASK   0x3f    /* Data repeat count mask               */
  14. #define PCX_PAL_MASK    0x03    /* Palette interpretation mask          */
  15. #define PCX_EPAL_FLAG   0x0c    /* Extended palette flag                */
  16. #define PCX_PAL_SIZE    16      /* File header palette size             */
  17. #define PCX_EPAL_SIZE   256     /* Extended palette size                */
  18. #define PCX_CGA_BKGND(x)        (x[0].red >> 4)    /* Background color  */
  19. #define PCX_CGA_BURST(x)        (x[1].red & 0x80)  /* Color burst       */
  20. #define PCX_CGA_SELECT(x)       (x[1].red & 0x40)  /* Palette selector  */
  21. #define PCX_CGA_INTENSITY(x)    (x[1].red & 0x20)  /* Intensity         */
  22. #define PCX_MAXLINESZ   640     /* Maximum PCX line buffer size         */
  23.  
  24. typedef int BOOL;       /* Boolean flag                                 */
  25. typedef unsigned char BYTE;     /* 8-bit data type                      */
  26. typedef unsigned int WORD;      /* 16-bit data type                     */
  27.  
  28. typedef struct pcx_pal  /* PCX palette array element                    */
  29. {
  30.   BYTE red;             /* Red intensity                                */
  31.   BYTE green;           /* Green intensity                              */
  32.   BYTE blue;            /* Blue intensity                               */
  33. }PCX_PAL;
  34. struct mypal_struct{
  35.     int r;
  36.     int g;
  37.     int b;
  38. }mypal[256];
  39.  
  40. typedef struct pcx_hdr  /* PCX file header (Version 5)                  */
  41. {
  42.   BYTE pcx_id;          /* Always 0x0a for PCX files                    */
  43.   BYTE version;         /* Version number                               */
  44.   BYTE encoding;        /* 1 = PCX run length encoding                  */
  45.   BYTE bppixel;         /* Number of bits/pixel per color plane         */
  46.   WORD xul;             /* X-position of upper left corner              */
  47.   WORD yul;             /* Y-position of upper left corner              */
  48.   WORD xlr;             /* X-position of lower right corner             */
  49.   WORD ylr;             /* Y-position of lower right corner             */
  50.   WORD horz_res;        /* Horizontal resolution                        */
  51.   WORD vert_res;        /* Vertical resolution                          */
  52.   PCX_PAL palette[PCX_PAL_SIZE];        /* Hardware R-G-B palette       */
  53.   BYTE reserved;        /* Unused in Version 5                          */
  54.   BYTE nplanes;         /* Number of color planes                       */
  55.   WORD bppscan;         /* Number of bytes per plane scan line          */
  56.   WORD palette_type;    /* Palette interpretation                       */
  57.   WORD scrn_width;      /* Horizontal screen size in pixels             */
  58.   WORD scrn_height;     /* Vertical screen size in pixels               */
  59.   BYTE filler[54];      /* Padding to fill out 128-byte header          */
  60.  
  61. }PCX_HDR;
  62.  
  63. typedef struct pcx_workblk      /* PCX image file workblock             */
  64. {
  65.   /* File header                                                        */
  66.  
  67.   FILE *fp;                     /* PCX image file pointer               */
  68.   PCX_HDR header;               /* PCX image file header                */
  69.   PCX_PAL *palettep;            /* Color palette pointer                */
  70.   BOOL epal_flag;               /* Extended color palette flag          */
  71.  
  72.   /* Image manipulation variables                                       */
  73.  
  74.   int num_bytes;                /* Number of bytes to display           */
  75.   int mask;                     /* Unseen pixels mask                   */
  76.   unsigned long page_offset;    /* Display page address offset          */
  77.  
  78.   /* Image manipulation function pointer                                */
  79.  
  80.   void (*pcx_funcp)(struct pcx_workblk *, unsigned char _far *, int);
  81. } PCX_WORKBLK;
  82.  
  83. typedef struct pcx_vsb  /* BIOS video services data save buffer         */
  84. {
  85.   struct pcx_ppt                /* Primary Pointer Table                */
  86.   {
  87.     void _far *vptp;            /* Video Parameter Table pointer        */
  88.     unsigned char _far *dsap;   /* Dynamic Save Area pointer            */
  89.     void _far *tmacgp;          /* Text Mode Aux Char Generator pointer */
  90.     void _far *gmacgp;          /* Graphics Mode Aux Char Generator ptr */
  91.     void _far *sptp;            /* Secondary Pointer Table pointer      */
  92.     void _far *rsv_1;           /* Reserved                             */
  93.     void _far *rsv_2;           /* Reserved                             */
  94.   } pcx_ppt;
  95.   struct pcx_ppt _far *prev_pptp;
  96. }PCX_VSB;
  97.  
  98. static BOOL pcx_encode(int, int, FILE *);
  99. static BOOL pcx_init_palette(PCX_PAL *, int);
  100. static BOOL pcx_write_extpal(FILE *);
  101. static BOOL pcx_write_line(unsigned char *, int, FILE *);
  102. static BOOL pcx_write_init(PCX_WORKBLK *, int, int, int, int);
  103. static void pcx_get_cga(PCX_WORKBLK *, unsigned char _far *, int);
  104. static void pcx_get_ega(PCX_WORKBLK *, unsigned char _far *, int);
  105. static void pcx_get_herc(PCX_WORKBLK *, unsigned char _far *, int);
  106. static void pcx_get_vga(PCX_WORKBLK *, unsigned char _far *, int);
  107. static BOOL pcx_read_init(PCX_WORKBLK *, int, int);
  108. static BOOL pcx_read_extpal(PCX_WORKBLK *);
  109. static BOOL pcx_read_header(PCX_WORKBLK *);
  110. static BOOL pcx_read_line(PCX_WORKBLK *, unsigned char *, int);
  111. static BOOL pcx_set_palette(PCX_PAL *, int);
  112. static void pcx_put_vga(PCX_WORKBLK *, unsigned char _far *, int);
  113. BOOL pcx_close(PCX_WORKBLK *);
  114. BOOL load_pcx(char *, char far *);
  115. PCX_WORKBLK *pcx_open(char *, BOOL);
  116. BOOL pcx_init_dsa(PCX_VSB **);
  117. BOOL pcx_isvga(void);
  118. void pcx_free_dsa(PCX_VSB *);
  119.  
  120.  
  121. char far *buf;
  122. char far *write_buf;
  123.  
  124.  
  125. static BYTE pcx_EGA_DefPal_1[16] =      /* Modes 0x0d and 0x0e          */
  126. {
  127.   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
  128.   0x14, 0x15, 0x16, 0x17
  129. };
  130.  
  131. static BYTE pcx_EGA_DefPal_2[16] =      /* Mode 0x0f                    */
  132. {
  133.   0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
  134.   0x00, 0x18, 0x00, 0x00
  135. };
  136.  
  137. static BYTE pcx_EGA_DefPal_3[16] =      /* Mode 0x10                    */
  138. {
  139.   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 
  140.   0x3c, 0x3d, 0x3e, 0x3f
  141. };
  142.  
  143.  
  144.  
  145. BOOL load_pcx(char *fname, char far *buffer)
  146. {
  147.     int bpline;                   /* Number of bytes per scan line        */
  148.     int line_num;                 /* Scan line number                     */
  149.     int max_lines;                /* Maximum number of scan lines         */
  150.     unsigned char *linep;         /* PCX scan line buffer pointer         */
  151.     BOOL status = TRUE;           /* Return status                        */
  152.     PCX_WORKBLK *wbp;             /* PCX image file workblock pointer     */
  153.     int vmode=0x13,page=0;
  154.  
  155.     buf=buffer;
  156.     /* Open a PCX image file workblock                                    */
  157.     if ((wbp = pcx_open(fname, FALSE)) == (PCX_WORKBLK *) NULL)
  158.         return (FALSE);
  159.     /* Initialize the workblock for reading                               */
  160.     if (pcx_read_init(wbp, vmode, page) == FALSE)
  161.     {
  162.         (void) pcx_close(wbp);      /* Close the PCX workblock              */
  163.         return (FALSE);
  164.     }
  165.     /* Calculate the image height                                         */
  166.     max_lines = wbp->header.yul + wbp->header.ylr + 1;
  167.     /* Calculate number of bytes per line (for all color planes)          */
  168.     bpline = wbp->header.bppscan * wbp->header.nplanes;
  169.     /* Allocate the PCX scan line buffer                                  */
  170.     if ((linep = (unsigned char *) malloc(bpline)) != (unsigned char *)NULL)
  171.     {
  172.         /* Set the file pointer to the beginning of the encoded image data  */
  173.  
  174.         if (fseek(wbp->fp, (long) (sizeof(PCX_HDR)), SEEK_SET) != 0)
  175.             status = FALSE;
  176.         if (pcx_set_palette(wbp->palettep, vmode) == FALSE)
  177.             status = FALSE;
  178.         /* Read the image line by line                                      */
  179.         for (line_num = 0; line_num < max_lines; line_num++)
  180.         {
  181.             /* Read the current scan line                                   */
  182.             if ((status = pcx_read_line(wbp, linep, bpline)) == FALSE)
  183.             {
  184.                 status = FALSE;
  185.                 break;
  186.             }
  187.             /* Display the current scan line                                */
  188.             wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);
  189.             free(linep);        /* Free the PCX scan line buffer         */
  190.         }
  191.     }
  192.     else
  193.         status = FALSE;
  194.     if (pcx_close(wbp) == FALSE)  /* Close the PCX workblock              */
  195.         status = FALSE;
  196.  
  197.     return (status);
  198. }
  199.  
  200.  
  201. static BOOL pcx_read_init(PCX_WORKBLK *wbp,int vmode,int page)
  202. {
  203.     int width;                    /* Display width                        */
  204.     int leftover;                 /* Number of unseen bits                */
  205.     BOOL status = TRUE;           /* Return status                        */
  206.  
  207.     /* Read the file header                                               */
  208.  
  209.     if ((pcx_read_header(wbp)) == FALSE)
  210.         return (FALSE);
  211.  
  212.     /* Initialize the workblock color palette pointer                     */
  213.  
  214.     wbp->palettep = wbp->header.palette;
  215.     wbp->epal_flag = FALSE;
  216.  
  217.     /* Read the extended palette (if any)                                 */
  218.  
  219.         if (pcx_read_extpal(wbp) == FALSE)
  220.             return (FALSE);
  221.  
  222.     /* Initialize the display page address offset                         */
  223.  
  224.     wbp->page_offset = (unsigned long) 0L;
  225.     /* Calculate number of bytes to display                           */
  226.     wbp->num_bytes = min((wbp->header.xlr - wbp->header.xul + 1), 320);
  227.     wbp->mask = 0;  /* Dummy parameter                                */
  228.     wbp->pcx_funcp = pcx_put_vga;     /* Set the display function ptr */
  229.  
  230.  
  231.     return (status);
  232. }
  233.  
  234.  
  235. static BOOL pcx_read_header(PCX_WORKBLK *wbp)
  236. {
  237.     BOOL status = TRUE;   /* Status flag                                  */
  238.     PCX_HDR *hdrp;        /* PCX file header buffer pointer               */
  239.  
  240.     hdrp = &(wbp->header);        /* Initialize the file header pointer   */
  241.  
  242.     /* Read the file header                                               */
  243.  
  244.     if (fseek(wbp->fp, 0L, SEEK_SET) != 0)
  245.         status = FALSE;
  246.     if (fread(hdrp, sizeof(PCX_HDR), 1, wbp->fp) != 1)
  247.         status = FALSE;
  248.     /* Validate the PCX file format                                       */
  249.     if ((hdrp->pcx_id != 0x0a) || (hdrp->encoding != 1))
  250.         status = FALSE;
  251.     return (status);
  252. }
  253.  
  254.  
  255. static BOOL pcx_read_extpal( PCX_WORKBLK *wbp )
  256. {
  257.     int indicator;        /* PCX extended palette indicator               */
  258.  
  259.     /* Position the file pointer to the extended palette indicator byte   */
  260.  
  261.     if (fseek(wbp->fp, -769L, SEEK_END) != 0)
  262.         return (FALSE);
  263.  
  264.     /* Read the (assumed) extended palette indicator byte                 */
  265.  
  266.     if ((indicator = getc(wbp->fp)) == EOF)
  267.         return (FALSE);
  268.  
  269.     if (indicator == PCX_EPAL_FLAG)       /* Check for indicator byte     */
  270.     {
  271.         /* Allocate an extended palette buffer                              */
  272.  
  273.         if ((wbp->palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL),
  274.         PCX_EPAL_SIZE)) == (PCX_PAL *) NULL)
  275.             return (FALSE);
  276.  
  277.         /* Read the extended palette                                        */
  278.  
  279.         if (fread(wbp->palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, wbp->fp) !=
  280.             PCX_EPAL_SIZE)
  281.         {
  282.             free(wbp->palettep);      /* Free the extended palette buffer     */
  283.             return (FALSE);
  284.         }
  285.  
  286.         wbp->epal_flag = TRUE;      /* Indicate extended palette present    */
  287.     }
  288.  
  289.     return (TRUE);
  290. }
  291.  
  292.  
  293. static BOOL pcx_read_line(PCX_WORKBLK *wbp,unsigned char *linep,int bpline)
  294. {
  295.     int data;             /* Image data byte                              */
  296.     int count;            /* Image data byte repeat count                 */
  297.     int offset = 0;       /* Scan line buffer offset                      */
  298.  
  299.     while (offset < bpline)       /* Decode current scan line             */
  300.     {
  301.         if ((data = getc(wbp->fp)) == EOF)  /* Get next byte                */
  302.             return (FALSE);
  303.  
  304.         /* If top two bits of byte are set, lower six bits show how         */
  305.         /* many times to duplicate next byte                                */
  306.  
  307.         if ((data & PCX_COMP_FLAG) == PCX_COMP_FLAG)
  308.         {
  309.             count = data & PCX_COMP_MASK;     /* Mask off repeat count        */
  310.  
  311.             if ((data = getc(wbp->fp)) == EOF)        /* Get next byte        */
  312.                 return (FALSE);
  313.  
  314.             memset(linep, data, count);       /* Duplicate byte               */
  315.             linep += count;
  316.             offset += count;
  317.         }
  318.         else
  319.         {
  320.             *linep++ = (unsigned char) data;  /* Copy byte                    */
  321.             offset++;
  322.         }
  323.     }
  324.  
  325.     return (TRUE);
  326. }
  327.  
  328. static BOOL pcx_set_palette(PCX_PAL *palettep,int vmode)
  329. {
  330.     int i;                        /* Scratch counter                      */
  331.  
  332.     for (i = 0; i < PCX_EPAL_SIZE; i++)
  333.         pcx_setDAC(i,palettep[i].red >> 2,palettep[i].green>>2,palettep[i].blue>>2);
  334.     return (TRUE);
  335. }
  336.  
  337. pcx_setDAC(int n,int r,int g,int b)
  338. {
  339.     outp(0x3c8,n);
  340.     outp(0x3c9,r);
  341.     outp(0x3c9,g);
  342.     outp(0x3c9,b);
  343.     mypal[n].r=r;
  344.     mypal[n].g=g;
  345.     mypal[n].b=b;
  346. }
  347.  
  348.  
  349. static void pcx_put_vga(PCX_WORKBLK *wbp,unsigned char _far *linep,int line_num)
  350. {
  351.     unsigned char _far *displayp;         /* Display buffer pointer       */
  352.  
  353.     /* Calculate buffer pointer                                           */
  354.  
  355.     displayp = (unsigned char _far *)buf + line_num * 320;
  356.  
  357.     /* Copy data from the scan line buffer to the VGA display buffer      */
  358.  
  359.     (void) _fmemcpy(displayp, linep, wbp->num_bytes);
  360. }
  361.  
  362. PCX_WORKBLK *pcx_open
  363. (
  364.   char *fname,
  365.   BOOL wrt_flag
  366. )
  367. {
  368.   PCX_WORKBLK *wbp;     /* PCX image file workblock pointer             */
  369.  
  370.   /* Allocate a workblock                                               */
  371.  
  372.   if ((wbp = (PCX_WORKBLK *) malloc(sizeof(PCX_WORKBLK))) == NULL)
  373.     return (NULL);
  374.  
  375.   /* Open the PCX image file in binary mode                             */
  376.  
  377.   if (wrt_flag == FALSE)
  378.     wbp->fp = fopen(fname, "rb");       /* Open for reading             */
  379.   else
  380.     wbp->fp = fopen(fname, "wb");       /* Open for writing             */
  381.  
  382.   if (wbp->fp == NULL)  /* Check for successful file opening            */
  383.   {
  384.     free(wbp);          /* Free the workblock memory                    */
  385.     return (NULL);
  386.   }
  387.  
  388.   return (wbp);         /* Return the workblock pointer                 */
  389. }
  390.  
  391.  
  392. BOOL pcx_close
  393. (
  394.   PCX_WORKBLK *wbp
  395. )
  396. {
  397.   free(wbp->palettep);  /* Free the extended palette (if it exists)     */
  398.  
  399.   free(wbp);            /* Free the PCX image file workblock            */
  400.  
  401.   if (fclose(wbp->fp) == EOF)   /* Close the PCX image file             */
  402.     return (FALSE);
  403.  
  404.   return (TRUE);
  405. }
  406.  
  407.  
  408. BOOL pcx_isvga(void)
  409. {
  410.   unsigned char *vinfop;        /* VGA information buffer pointer       */
  411.   union REGS regs;              /* 80x86 register values                */
  412.   struct SREGS sregs;           /* 80x86 segment register values        */
  413.  
  414.   /* Allocate a VGA functionality/state information buffer              */
  415.  
  416.   if ((vinfop = (unsigned char *) malloc(sizeof(unsigned char) * 64)) ==
  417.       NULL)
  418.     return (FALSE);
  419.  
  420.   /* Attempt to read the VGA information                                */
  421.  
  422.   regs.h.ah = 0x1b;     /* Select "Return VGA Info" BIOS routine        */
  423.   regs.x.bx = 0;        /* Implementation type                          */
  424.  
  425.   /* Get the VGA information buffer offset value                        */
  426.  
  427.   regs.x.di = (unsigned int) vinfop;
  428.  
  429.   segread(&sregs);      /* Get the current DS segment register value    */
  430.  
  431.   sregs.es = sregs.ds;
  432.  
  433.   int86x(0x10, ®s, ®s, &sregs);   /* Call BIOS video service      */
  434.  
  435.   free(vinfop);         /* Free the VGA information buffer              */
  436.  
  437.   /* The value 0x1b is returned in register AL only if a VGA display    */
  438.   /* adapter is present                                                 */
  439.  
  440.   if (regs.h.al == 0x1b)
  441.     return (TRUE);
  442.   else
  443.     return (FALSE);
  444. }
  445.  
  446.  
  447. BOOL save_pcx(char *fname,char far * buffer)
  448. {
  449.   int bpline;                   /* Number of bytes per scan line        */
  450.   int line_num;                 /* Scan line number                     */
  451.   unsigned char *linep;         /* Image scan line buffer pointer       */
  452.   BOOL status = TRUE;           /* Return status                        */
  453.   PCX_WORKBLK *wbp;             /* PCX image file workblock pointer     */
  454.   int width=320;
  455.   int height=200;
  456.   int vmode=0x13;
  457.   int page=0;
  458.  
  459.     write_buf=buffer;
  460.  
  461.   /* Open a PCX image file workblock                                    */
  462.  
  463.   if ((wbp = pcx_open(fname, TRUE)) == (PCX_WORKBLK *) NULL)
  464.     return (FALSE);
  465.  
  466.   /* Initialize the workblock for writing                               */
  467.  
  468.   if (pcx_write_init(wbp, vmode, page, width, height) == FALSE)
  469.     status = FALSE;
  470.  
  471.   /* Calculate number of bytes per line (for all color planes)          */
  472.  
  473.   bpline = wbp->header.bppscan * wbp->header.nplanes;
  474.  
  475.   /* Allocate a scan line buffer                                        */
  476.  
  477.   if (status == TRUE)
  478.     if ((linep = (unsigned char *) malloc(bpline)) == (unsigned char *)
  479.         NULL)
  480.       status = FALSE;
  481.  
  482.   /* Write the file header to the file                                  */
  483.  
  484.   if (status == TRUE)
  485.     if (fwrite(&(wbp->header), sizeof(PCX_HDR), 1, wbp->fp) != 1)
  486.       status = FALSE;
  487.  
  488.   /* Write the encoded image data to the file                           */
  489.  
  490.   if (status == TRUE)
  491.   {
  492.     for (line_num = 0; line_num <= (int) wbp->header.ylr; line_num++)
  493.     {
  494.       /* Get the current video buffer scan line                         */
  495.  
  496.       wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);
  497.  
  498.       /* Encode the scan line and write it to the file                  */
  499.  
  500.       if (pcx_write_line(linep, bpline, wbp->fp) == FALSE)
  501.       {
  502.         status = FALSE;
  503.         break;
  504.       }
  505.     }
  506.   }
  507.     if (status == TRUE)
  508.       if (pcx_write_extpal(wbp->fp) == FALSE)
  509.         status = FALSE;
  510.   if (pcx_close(wbp) == FALSE)  /* Close the PCX workblock              */
  511.     status = FALSE;
  512.  
  513.   free(linep);          /* Free the scan line buffer                    */
  514.  
  515.   /* Remove the PCX image file if an error occurred                     */
  516.  
  517.   if (status == FALSE)
  518.     (void) remove(fname);
  519.  
  520.   return (status);
  521. }
  522.  
  523.  
  524. BOOL pcx_init_dsa
  525. (
  526.   PCX_VSB **vsbpp
  527. )
  528. {
  529.   unsigned char _far *dsap;     /* Dynamic Save Area pointer            */
  530.   PCX_VSB *vsbp;                /* Video services data save buffer ptr  */
  531.  
  532.   *vsbpp = (PCX_VSB *) NULL;    /* Initialize returned pointer          */
  533.  
  534.   /* Allocate a Dynamic Save Area buffer                                */
  535.  
  536.   if ((dsap = (unsigned char _far *) _fmalloc(sizeof(unsigned char) *
  537.       256)) == (unsigned char _far *) NULL)
  538.     return (FALSE);
  539.  
  540.   /* Allocate a BIOS video services data save buffer                    */
  541.  
  542.   if ((vsbp = (PCX_VSB *) malloc(sizeof(PCX_VSB))) == (PCX_VSB *) NULL)
  543.   {
  544.     _ffree(dsap);       /* Free the Dynamic Save Area buffer            */
  545.     return (FALSE);
  546.   }
  547.  
  548.   /* Save the existing Primary Pointer Table pointer                    */
  549.  
  550.   vsbp->prev_pptp = *((struct pcx_ppt _far * _far *) 0x004000a8L);
  551.  
  552.   /* Copy the existing Primary Pointer Table into the buffer            */
  553.  
  554.   (void) _fmemcpy((struct pcx_ppt _far *) &(vsbp->pcx_ppt),
  555.       vsbp->prev_pptp, sizeof(struct pcx_ppt));
  556.  
  557.   vsbp->pcx_ppt.dsap = dsap;    /* Update the Dynamic Save Area ptr     */
  558.  
  559.   /* Update the Primary Pointer Table pointer in the Video Save Table   */
  560.  
  561.   *((struct pcx_ppt _far * _far *) 0x004000a8L) = &(vsbp->pcx_ppt);
  562.  
  563.   *vsbpp = vsbp;        /* Return Video Services data save buffer ptr   */
  564.  
  565.   return (TRUE);
  566. }
  567.  
  568.  
  569. void pcx_free_dsa
  570. (
  571.   PCX_VSB *vsbp
  572. )
  573. {
  574.   /* Restore the previous primary pointer table pointer                 */
  575.  
  576.   *((struct pcx_ppt _far * _far *) 0x004000a8L) = vsbp->prev_pptp;
  577.  
  578.   _ffree(vsbp->pcx_ppt.dsap);   /* Free the Dynamic Save Area           */
  579.  
  580.   free(vsbp);   /* Free the Video Services data save buffer             */
  581. }
  582.  
  583.  
  584. static BOOL pcx_write_init
  585. (
  586.   PCX_WORKBLK *wbp,
  587.   int vmode,
  588.   int page,
  589.   int width,
  590.   int height
  591. )
  592. {
  593.   int max_width;        /* Maximum image width                          */
  594.   int max_height;       /* Maximum image height                         */
  595.   int shift;            /* Mask shift value                             */
  596.   BOOL status = TRUE;   /* Return status                                */
  597.   PCX_HDR *hdrp;        /* File header buffer pointer                   */
  598.  
  599.   /* Initialize the display page address offset                         */
  600.  
  601.   wbp->page_offset = (unsigned long) 0L;
  602.  
  603.   hdrp = &(wbp->header);        /* Initialize the file header pointer   */
  604.  
  605.   /* Initialize the header constants                                    */
  606.  
  607.   hdrp->pcx_id = 0x0a;          /* PCX format identifier                */
  608.   hdrp->version = 5;            /* Version number                       */
  609.   hdrp->encoding = 1;           /* Encoding format (run-length)         */
  610.   hdrp->xul = 0;                /* Upper left x-position                */
  611.   hdrp->yul = 0;                /* Upper left y-position                */
  612.   hdrp->reserved = 0;           /* (Used to be video mode)              */
  613.   hdrp->palette_type = 1;       /* Color or b&w palette type            */
  614.  
  615.   memset(hdrp->filler, 0, sizeof(hdrp->filler));        /* Padding      */
  616.  
  617.   /* Initialize the video mode-dependent parameters                     */
  618.  
  619.  
  620.       max_width = min(width, 320);      /* Maximum image width          */
  621.       max_height = min(height, 200);    /* Maximum image height         */
  622.  
  623.       hdrp->bppixel = 8;                /* Bits per pixel               */
  624.       hdrp->horz_res = 320;             /* Horizontal resolution        */
  625.       hdrp->vert_res = 200;             /* Vertical resolution          */
  626.       hdrp->nplanes = 1;                /* Number of color planes       */
  627.  
  628.       /* Calculate number of bytes to copy                              */
  629.  
  630.       wbp->num_bytes = max_width;
  631.  
  632.       shift = 0;        /* Dummy parameter                              */
  633.  
  634.       wbp->pcx_funcp = pcx_get_vga;     /* Set display capture fcn ptr  */
  635.  
  636.  
  637.   /* Initialize common video mode-dependent parameters                  */
  638.  
  639.   hdrp->xlr = max_width - 1;            /* Lower right x-position       */
  640.   hdrp->ylr = max_height - 1;           /* Lower right y-position       */
  641.   hdrp->scrn_width = hdrp->horz_res;    /* Screen width                 */
  642.   hdrp->scrn_height = hdrp->vert_res;   /* Screen height                */
  643.  
  644.   /* Calculate mask for "white" data                                    */
  645.  
  646.   if (shift != 0)
  647.     wbp->mask = 0xff >> shift;
  648.   else
  649.     wbp->mask = 0x00;
  650.  
  651.   /* Initialize the file header palette                                 */
  652.  
  653.   status = pcx_init_palette(hdrp->palette, vmode);
  654.  
  655.   /* Calculate number of bytes per color plane scan line (must be an    */
  656.   /* even number of bytes)                                              */
  657.  
  658.   hdrp->bppscan = 2 * (((((hdrp->xlr * hdrp->bppixel) + 7) / 8) + 1) / 2);
  659.  
  660.   return (status);
  661. }
  662.  
  663.  
  664. static BOOL pcx_init_palette
  665. (
  666.   PCX_PAL *palettep,
  667.   int vmode
  668. )
  669. {
  670.   int i;                        /* Scratch counter                      */
  671.   int val;                      /* Current palette register value       */
  672.   int red;                      /* Temporary value                      */
  673.   int green;                    /* Temporary value                      */
  674.   int blue;                     /* Temporary value                      */
  675.   unsigned char *ega_palp;      /* EGA/VGA palette buffer pointer       */
  676.   unsigned char _far *dsap;     /* Dynamic Save Area pointer            */
  677.   union REGS regs;              /* 80x86 register values                */
  678.   struct SREGS sregs;           /* 80x86 segment register values        */
  679.  
  680.  
  681.     memset(palettep, 0, sizeof(PCX_PAL) * PCX_PAL_SIZE);
  682.  
  683.   return (TRUE);
  684. }
  685.  
  686. static BOOL pcx_write_line
  687. (
  688.   unsigned char *linep,
  689.   int buflen,
  690.   FILE *fp
  691. )
  692. {
  693.   int curr_data;        /* Current data byte                            */
  694.   int prev_data;        /* Previous data byte                           */
  695.   int data_count;       /* Data repeat count                            */
  696.   int line_count;       /* Scan line byte count                         */
  697.  
  698.   prev_data = *linep++;         /* Initialize the previous data byte    */
  699.   data_count = 1;
  700.   line_count = 1;
  701.  
  702.   while (line_count < buflen)   /* Encode scan line                     */
  703.   {
  704.     curr_data = *linep++;       /* Get the current data byte            */
  705.     line_count++;               /* Increment the scan line counter      */
  706.  
  707.     if (curr_data == prev_data)         /* Repeating data bytes ?       */
  708.     {
  709.       data_count++;     /* Increment the data repeat count              */
  710.  
  711.       /* Check for maximum allowable repeat count                       */
  712.  
  713.       if (data_count == PCX_COMP_MASK)
  714.       {
  715.         /* Encode the data                                              */
  716.  
  717.         if (pcx_encode(prev_data, data_count, fp) == FALSE)
  718.           return (FALSE);
  719.  
  720.         data_count = 0;         /* Reset the data repeat count          */
  721.       }
  722.     }
  723.     else    /* End of repeating data bytes                              */
  724.     {
  725.       if (data_count > 0)
  726.       {
  727.         /* Encode the data                                              */
  728.  
  729.         if (pcx_encode(prev_data, data_count, fp) == FALSE)
  730.           return (FALSE);
  731.       }
  732.  
  733.       prev_data = curr_data;    /* Current data byte now previous       */
  734.       data_count = 1;
  735.     }
  736.   }
  737.  
  738.   if (data_count > 0)   /* Any remaining data ?                         */
  739.   {
  740.     /* Encode the data                                                  */
  741.  
  742.     if (pcx_encode(prev_data, data_count, fp) == FALSE)
  743.       return (FALSE);
  744.   }
  745.  
  746.   return (TRUE);
  747. }
  748.  
  749. static BOOL pcx_encode
  750. (
  751.   int data,
  752.   int count,
  753.   FILE *fp
  754. )
  755. {
  756.   if (((data & PCX_COMP_FLAG) == PCX_COMP_FLAG) || count > 1)
  757.   {
  758.     /* Write the count byte                                             */
  759.  
  760.     if (putc(PCX_COMP_FLAG | count, fp) == EOF)
  761.       return (FALSE);
  762.   }
  763.  
  764.   /* Write the data byte                                                */
  765.  
  766.   if (putc(data, fp) == EOF)
  767.     return (FALSE);
  768.  
  769.   return (TRUE);
  770. }
  771.  
  772.  
  773. static BOOL pcx_write_extpal
  774. (
  775.   FILE *fp
  776. )
  777. {
  778.   int i;                        /* Scratch counter                      */
  779.   BOOL status = TRUE;           /* Return status                        */
  780.   PCX_PAL *palettep;            /* Extended PCX palette buffer pointer  */
  781.   unsigned char *vga_palp;      /* 256-color VGA palette buffer pointer */
  782.   union REGS regs;              /* 80x86 register values                */
  783.   struct SREGS sregs;           /* 80x86 segment register values        */
  784.  
  785.   /* Allocate an extended PCX palette buffer                            */
  786.  
  787.   if ((palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL), PCX_EPAL_SIZE)) ==
  788.       (PCX_PAL *) NULL)
  789.     return (FALSE);
  790.  
  791.   /* Allocate a 256-color VGA palette buffer                            */
  792.  
  793.   if ((vga_palp = (unsigned char *) calloc(sizeof(unsigned char), 768))
  794.       == (unsigned char *) NULL)
  795.   {
  796.     free(palettep);     /* Free the extended PCX palette buffer         */
  797.     return (FALSE);
  798.   }
  799.  
  800.   for (i = 0; i < PCX_EPAL_SIZE; i++)
  801.   {
  802.     palettep[i].red = mypal[i].r<<2;
  803.     palettep[i].green = mypal[i].g<<2;
  804.     palettep[i].blue = mypal[i].b<<2;
  805.   }
  806.  
  807.   /* Write the extended PCX palette indicator byte to the file          */
  808.  
  809.   if (status == TRUE)
  810.     if (fputc(PCX_EPAL_FLAG, fp) == EOF)
  811.       status = FALSE;
  812.  
  813.   /* Write the extended PCX palette to the file                         */
  814.  
  815.   if (status == TRUE)
  816.     if (fwrite(palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, fp) !=
  817.         PCX_EPAL_SIZE)
  818.       status = FALSE;
  819.  
  820.   free(palettep);       /* Free the extended PCX palette buffer         */
  821.  
  822.   free(vga_palp);       /* Free the VGA palette buffer                  */
  823.  
  824.   return (status);
  825. }
  826.  
  827. static void pcx_get_vga
  828. (
  829.   PCX_WORKBLK *wbp,
  830.   unsigned char _far *linep,
  831.   int line_num
  832. )
  833. {
  834.   unsigned char _far *displayp;         /* Display buffer pointer       */
  835.  
  836.   /* Calculate buffer pointer                                           */
  837.  
  838.   displayp = (unsigned char _far *) write_buf + line_num * 320;
  839.  
  840.   /* Copy data from the VGA display buffer to the scan line buffer      */
  841.  
  842.   (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  843.  
  844.   /* Pad scan line with "white" data byte (if necessary)                */
  845.  
  846.   if (wbp->num_bytes & 1)
  847.     linep[wbp->num_bytes] = 0xff;
  848. }
  849.  
  850.